

package ai.moran.demo.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.ParseContext;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import com.jayway.jsonpath.spi.json.JsonProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
import java.io.IOException;
import java.util.Map;

public class JsonUtility {
    private static ObjectMapper mapper = newMapper();
    private static final Configuration config = Configuration.builder().jsonProvider(new JacksonJsonNodeJsonProvider()).mappingProvider(new JacksonMappingProvider()).build();

    public JsonUtility() {
    }

    public static ObjectMapper newMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.enable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT);
        mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
        mapper.configure(Feature.ALLOW_COMMENTS, true);
        mapper.configure(Feature.ALLOW_SINGLE_QUOTES, true);
        mapper.configure(Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
        mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        mapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        mapper.configure(Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
        return mapper;
    }

    public static void enableCamelCaseToLowerCaseWithUnderscope(ObjectMapper objectMapper) {
        objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
    }

    public static ParseContext getParseContext() {
        return JsonPath.using(config);
    }

    public static JsonProvider getJsonProvider() {
        return config.jsonProvider();
    }

    public static String toJsonString(Object value) throws JsonProcessingException {
        return toJsonString(value, false);
    }

    public static String toJsonString(Object value, TypeReference<?> rootType) throws JsonProcessingException {
        return toJsonString(value, rootType, false);
    }

    public static String toJsonString(ObjectMapper objectMapper, Object value) throws JsonProcessingException {
        return toJsonString(objectMapper, value, false);
    }

    public static String toJsonString(Object value, boolean prettyFormat) throws JsonProcessingException {
        return prettyFormat ? mapper.writerWithDefaultPrettyPrinter().writeValueAsString(value) : mapper.writeValueAsString(value);
    }

    public static String toJsonString(Object value, TypeReference<?> rootType, boolean prettyFormat) throws JsonProcessingException {
        return prettyFormat ? mapper.writerWithDefaultPrettyPrinter().forType(rootType).writeValueAsString(value) : mapper.writerFor(rootType).writeValueAsString(value);
    }

    public static String toJsonString(ObjectMapper objectMapper, Object value, boolean prettyFormat) throws JsonProcessingException {
        return prettyFormat ? objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(value) : objectMapper.writeValueAsString(value);
    }

    public static <T> T toObject(String json, Class<T> typeClass) throws IOException {
        return mapper.readValue(json, typeClass);
    }

    public static <T> T toObject(ObjectMapper objectMapper, String json, Class<T> typeClass) throws IOException {
        return objectMapper.readValue(json, typeClass);
    }

    public static <T> T toObject(ObjectMapper objectMapper, String json, TypeReference typeReference) throws IOException {
        return (T) objectMapper.readValue(json, typeReference);
    }

    public static <T> T toObject(String json, TypeReference typeReference) throws IOException {
        return (T) mapper.readValue(json, typeReference);
    }

    public static Map<String, String> toStringKVMap(Object object) {
        return (Map)mapper.convertValue(object, new TypeReference<Map<String, String>>() {
        });
    }

    public static JsonNode toJsonNode(String value) throws IOException {
        return mapper.readTree(value);
    }

    public static ObjectMapper getMapper() {
        return mapper;
    }
}
